package com.xinlianshiye.im.utils;

import com.xinlianshiye.im.service.UserService;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.websocket.Session;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.Future;

@Getter
@Slf4j
@Component
@EnableScheduling
public class SessionManager {

    @Autowired
    private UserService userService;
    /**
     * 采用ConcurrentHashMap类,细化锁颗粒度
     */
    // 客户端用户（userId）和其连接的session列表
    private final ConcurrentHashMap<Integer, List<Session>> userOnline = new ConcurrentHashMap<>();
    // 所有session的集合
    private final ConcurrentHashMap<String, Session> allSession = new ConcurrentHashMap<>();
    // 记录空闲Session集合
    private final CopyOnWriteArraySet<Session> idle = new CopyOnWriteArraySet<>();
    // 记录正在使用中Session集合，value为Future，表示使用情况
    private final ConcurrentHashMap<Session, Future<Void>> busy = new ConcurrentHashMap<>();


    @Scheduled(fixedRate = 30*60*1000)  // 每隔多少秒执行1次
    public void refreshRedisOnlineInfo() throws IOException {
        log.debug("刷新websocket队列");
        for (Session session : allSession.values()) {
            if (!session.isOpen()) {
                onClose(session);
            }
        }
    }

    public Session getSessionById(String id) {
        return allSession.get(id);
    }

    public List<Session> getSessionByUserId(Integer userId) {
        List<Session> sessionList = userOnline.get(userId);
        if(sessionList == null || sessionList.isEmpty()) {
            return new ArrayList<>();
        }
        return sessionList;
    }

    // 判断该用户id 是否在线
    public boolean isUserOnline(Integer userId) {
        return userOnline.containsKey(userId);
    }

    private void addUserOnline(Session session, Integer userId) {
        userOnline.computeIfAbsent(userId, key -> new ArrayList<>()).add(session);
        idle.add(session);
    }

    public void onOpen(Session session) {
        Integer userId = userService.getUserId(session);
        log.info("开启session userId: {}, sessionId: {}", userId, session.getId());
        allSession.putIfAbsent(session.getId(), session);
        addUserOnline(session, userId);// 添加链接的session
    }

    public void onClose(Session session) throws IOException {
        Integer userId = userService.getUserId(session);
        log.info("关闭session userId: {}, sessionId: {}", userId, session.getId());
        if(session.isOpen()) {
            session.close();
        }
        if(userId != null) {
            List<Session> sessions1 = userOnline.get(userId);
            sessions1.remove(session);
        }
        allSession.remove(session.getId());
        idle.remove(session);
        busy.remove(session);
    }
}
